home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / imap-3.0 / ANSI / ipopd / ipop3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-06  |  12.9 KB  |  462 lines

  1. /*
  2.  * Program:    IPOP3D - IMAP2 to POP3 conversion server
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    1 November 1990
  13.  * Last Edited:    6 April 1993
  14.  *
  15.  * Copyright 1993 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36.  
  37. /* Parameter files */
  38.  
  39. #include "mail.h"
  40. #include "osdep.h"
  41. #include <stdio.h>
  42. #include <ctype.h>
  43. #include <pwd.h>
  44. #include "misc.h"
  45.  
  46.  
  47. /* Size of temporary buffers */
  48. #define TMPLEN 1024
  49.  
  50.  
  51. /* Server states */
  52.  
  53. #define AUTHORIZATION 0
  54. #define TRANSACTION 1
  55. #define UPDATE 2
  56.  
  57. /* Global storage */
  58.  
  59. char *version = "3.2(9)";    /* server version */
  60. int state = AUTHORIZATION;    /* server state */
  61. MAILSTREAM *stream = NIL;    /* mailbox stream */
  62. long nmsgs = 0;            /* current number of messages */
  63. long last = 0;            /* highest message accessed */
  64. long il = 0;            /* initial last message */
  65. char *host = NIL;        /* remote host name */
  66. char *user = NIL;        /* user name */
  67. char *pass = NIL;        /* password */
  68. long *msg = NIL;        /* message translation vector */
  69.  
  70.  
  71. /* Drivers we use */
  72.  
  73. extern DRIVER imapdriver,tenexdriver,mhdriver,mboxdriver,bezerkdriver;
  74.  
  75.  
  76. /* Function prototypes */
  77.  
  78. void main (int argc,char *argv[]);
  79. int login (char *t,int argc,char *argv[]);
  80. void blat (char *text,long lines);
  81.  
  82. extern char *crypt (char *key,char *salt);
  83.  
  84. /* Main program */
  85.  
  86. void main (int argc,char *argv[])
  87. {
  88.   long i,j,k;
  89.   char *s,*t;
  90.   char tmp[TMPLEN];
  91.   mail_link (&imapdriver);    /* install the IMAP driver */
  92.   mail_link (&tenexdriver);    /* install the Tenex mail driver */
  93.   mail_link (&mhdriver);    /* install the mh mail driver */
  94.   mail_link (&mboxdriver);    /* install the mbox mail driver */
  95.   mail_link (&bezerkdriver);    /* install the Berkeley mail driver */
  96.   printf ("+OK POP3 %s w/IMAP2 client (Comments to MRC@CAC.Washington.EDU)\015\012"
  97.       ,version);
  98.   fflush (stdout);        /* dump output buffer */
  99.                 /* command processing loop */
  100.   while ((state != UPDATE) && fgets (tmp,TMPLEN-1,stdin)) {
  101.                 /* find end of line */
  102.     if (!strchr (tmp,'\012')) puts ("-ERR Command line too long\015");
  103.     else if (!(s = strtok (tmp," \015\012"))) puts ("-ERR Null command\015");
  104.     else {            /* dispatch based on command */
  105.       ucase (s);        /* canonicalize case */
  106.                 /* snarf argument */
  107.       t = strtok (NIL,"\015\012");
  108.                 /* QUIT command always valid */
  109.       if (!strcmp (s,"QUIT")) state = UPDATE;
  110.       else switch (state) {    /* else dispatch based on state */
  111.       case AUTHORIZATION:    /* waiting to get logged in */
  112.     if (!strcmp (s,"USER")) {
  113.       fs_give ((void **) &host);
  114.       fs_give ((void **) &user);
  115.       if (t && *t) {    /* if user name given */
  116.                 /* remote user name? */
  117.         if (s = strchr (t,':')) {
  118.           *s++ = '\0';    /* tie off host name */
  119.           host = cpystr (t);/* copy host name */
  120.           user = cpystr (s);/* copy user name */
  121.         }
  122.                 /* local user name */
  123.         else user = cpystr (t);
  124.         puts ("+OK User name accepted, password please\015");
  125.       }
  126.       else puts ("-ERR Missing username argument\015");
  127.     }
  128.     else if (user && *user && !strcmp (s,"PASS"))
  129.       state = login (t,argc,argv);
  130.                 /* (chuckle) */
  131.     else if (!strcmp (s,"RPOP")) puts ("-ERR Nice try, bunkie\015");
  132.     else puts ("-ERR Unknown command in AUTHORIZATION state\015");
  133.     break;
  134.  
  135.       case TRANSACTION:        /* logged in */
  136.     if (!strcmp (s,"STAT")) {
  137.       for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
  138.         if (msg[i] > 0) {    /* message still exists? */
  139.           j++;        /* count one more undeleted message */
  140.           k += mail_elt (stream,msg[i])->rfc822_size;
  141.         }
  142.       printf ("+OK %d %d\015\012",j,k);
  143.     }
  144.     else if (!strcmp (s,"LIST")) {
  145.       if (t && *t) {    /* argument do single message */
  146.         if (((i = atoi (t)) > 0) && (i <= nmsgs) && (msg[i] >0))
  147.           printf ("+OK %d %d\015\012",i,
  148.               mail_elt(stream,msg[i])->rfc822_size);
  149.         else puts ("-ERR No such message\015");
  150.       }
  151.       else {        /* entire mailbox */
  152.         puts ("+OK Mailbox scan listing follows\015");
  153.         for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] > 0)
  154.           printf ("%d %d\015\012",i,mail_elt (stream,msg[i])->rfc822_size);
  155.         puts (".\015");    /* end of list */
  156.       }
  157.     }
  158.     else if (!strcmp (s,"RETR")) {
  159.       if (t && *t) {    /* must have an argument */
  160.         if (((i = atoi (t)) > 0) && (i <= nmsgs) && (msg[i] > 0)) {
  161.                 /* update highest message accessed */
  162.           if (i > last) last = i;
  163.           printf ("+OK %d octets\015\012",
  164.               mail_elt (stream,msg[i])->rfc822_size);
  165.                 /* output message */
  166.           blat (mail_fetchheader (stream,msg[i]),-1);
  167.           blat (mail_fetchtext (stream,msg[i]),-1);
  168.           puts (".\015");    /* end of list */
  169.         }
  170.         else puts ("-ERR No such message\015");
  171.       }
  172.       else puts ("-ERR Missing message number argument\015");
  173.     }
  174.     else if (!strcmp (s,"DELE")) {
  175.       if (t && *t) {    /* must have an argument */
  176.         if (((i = atoi (t)) > 0) && (i <= nmsgs) && (msg[i] > 0)) {
  177.                 /* update highest message accessed */
  178.           if (i > last) last = i;
  179.                 /* delete message */
  180.           sprintf (tmp,"%d",msg[i]);
  181.           mail_setflag (stream,tmp,"\\Deleted");
  182.           msg[i] = -msg[i];    /* note that we deleted this message */
  183.           puts ("+OK Message deleted\015");
  184.         }
  185.         else puts ("-ERR No such message\015");
  186.       }
  187.       else puts ("-ERR Missing message number argument\015");
  188.     }
  189.  
  190.     else if (!strcmp (s,"NOOP")) puts ("+OK No-op to you too!\015");
  191.     else if (!strcmp (s,"LAST")) printf ("+OK %d\015\012",last);
  192.     else if (!strcmp (s,"RSET")) {
  193.       if (nmsgs) {        /* undelete and unmark all of our messages */
  194.         for (i = 1; i <= nmsgs; i++) {
  195.                 /* ugly and inefficient, but trustworthy */
  196.           if (msg[i] < 0) {
  197.         sprintf (tmp,"%d",msg[i] = -msg[i]);
  198.         mail_clearflag (stream,tmp,i <= il ? "\\Deleted" :
  199.                   "\\Deleted \\Seen");
  200.           }
  201.           else if (i > il) {
  202.         sprintf (tmp,"%d",msg[i]);
  203.         mail_clearflag (stream,tmp,"\\Seen");
  204.           }
  205.         }
  206.         last = il;
  207.       }
  208.       puts ("+OK Reset state\015");
  209.     }
  210.     else if (!strcmp (s,"TOP")) {
  211.       if (t && *t) {    /* must have an argument */
  212.         if (((i = strtol (t,&t,10)) > 0) && (i <= nmsgs) && t && *t &&
  213.         ((j = atoi (t)) >= 0) && (msg[i] > 0)) {
  214.                 /* update highest message accessed */
  215.           if (i > last) last = i;
  216.           puts ("+OK Top of message follows\015");
  217.                 /* output message */
  218.           blat (mail_fetchheader (stream,msg[i]),-1);
  219.           blat (mail_fetchtext (stream,msg[i]),j);
  220.           puts (".\015");    /* end of list */
  221.         }
  222.         else puts ("-ERR Bad argument or no such message\015");
  223.       }
  224.       else puts ("-ERR Missing message number argument\015");
  225.     }
  226.     else if (!strcmp (s,"XTND")) puts ("-ERR Sorry I can't do that\015");
  227.     else puts ("-ERR Unknown command in TRANSACTION state\015");
  228.     break;
  229.       default:
  230.         puts ("-ERR Server in unknown state\015");
  231.     break;
  232.       }
  233.     }
  234.     fflush (stdout);        /* make sure output finished */
  235.   }
  236.                 /* expunge mailbox if a stream open */
  237.   if (stream && nmsgs) mail_expunge (stream);
  238.                 /* clean up the stream */
  239.   if (stream) mail_close (stream);
  240.   puts ("+OK Sayonara\015");    /* "now it's time to say sayonara..." */
  241.   fflush (stdout);        /* make sure output finished */
  242.   exit (0);            /* all done */
  243. }
  244.  
  245. /* Parse PASS command
  246.  * Accepts: pointer to command argument
  247.  * Returns: new state
  248.  */
  249.  
  250. int login (char *t,int argc,char *argv[])
  251. {
  252.   long i,j;
  253.   char tmp[TMPLEN];
  254.   struct passwd *pwd = getpwnam ("nobody");
  255.   MESSAGECACHE *elt;
  256.   fs_give ((void **) &pass);    /* flush old passowrd */
  257.   if (!(t && *t)) {        /* if no password given */
  258.     puts ("-ERR Missing password argument\015");
  259.     return AUTHORIZATION;
  260.   }
  261.   pass = cpystr (t);        /* copy password argument */
  262.   if (host) {            /* remote; build remote INBOX */
  263.     sprintf (tmp,"{%s}INBOX",host);
  264.     if (pwd) {            /* try to become someone harmless */
  265.       setgid (pwd->pw_gid);    /* set group ID */
  266.       setuid (pwd->pw_uid);    /* and user ID */
  267.     }
  268.   }
  269.                 /* local; attempt login, select INBOX */
  270.   else if (server_login (user,pass,NIL,argc,argv)) strcpy (tmp,"INBOX");
  271.   else {
  272.     puts ("-ERR Bad login\015");/* vague error message to confuse crackers */
  273.     return AUTHORIZATION;
  274.   }
  275.   nmsgs = 0;            /* no messages yet */
  276.   if (msg) fs_give ((void **) &msg);
  277.                 /* if mailbox non-empty */
  278.   if ((stream = mail_open (stream,tmp,NIL)) && (j = stream->nmsgs)) {
  279.     sprintf (tmp,"1:%d",j);    /* fetch fast information for all messages */
  280.     mail_fetchfast (stream,tmp);
  281.     msg = (long *) fs_get ((stream->nmsgs + 1) * sizeof (long));
  282.     for (i = 1; i <= j; i++) if (!(elt = mail_elt (stream,i))->deleted) {
  283.       msg[++nmsgs] = i;        /* note the presence of this message */
  284.       if (elt->seen) il = last = nmsgs;
  285.     }
  286.   }
  287.   printf ("+OK Mailbox open, %d messages\015\012",nmsgs);
  288.   return TRANSACTION;
  289. }
  290.  
  291. /* Blat a string with dot checking
  292.  * Accepts: string
  293.  *        maximum number of lines if greater than zero
  294.  * This routine is uglier and kludgier than it should be, just to be robust
  295.  * in the case of a Tenex-format message which doesn't end in a newline.
  296.  */
  297.  
  298. void blat (char *text,long lines)
  299. {
  300.   char c = *text++;
  301.   char d = *text++;
  302.   char e;
  303.                 /* no-op if zero lines or empty string */
  304.   if (!(lines && c && d)) return;
  305.   if (c == '.') putchar ('.');    /* double string-leading dot if necessary */
  306.   while (e = *text++) {        /* copy loop */
  307.     putchar (c);        /* output character */
  308.     if (c == '\012') {        /* end of line? */
  309.       if (!--lines) return;    /* count down another line, return if done */
  310.                 /* double leading dot as necessary */
  311.       if (d == '.') putchar ('.');
  312.     }
  313.     c = d; d = e;        /* move to next character */
  314.   }
  315.   puts ("\015");        /* output newline instead of last 2 chars */
  316. }
  317.  
  318. /* Co-routines from MAIL library */
  319.  
  320.  
  321. /* Message matches a search
  322.  * Accepts: IMAP2 stream
  323.  *        message number
  324.  */
  325.  
  326. void mm_searched (MAILSTREAM *stream,long msgno)
  327. {
  328.   /* Never called */
  329. }
  330.  
  331.  
  332. /* Message exists (i.e. there are that many messages in the mailbox)
  333.  * Accepts: IMAP2 stream
  334.  *        message number
  335.  */
  336.  
  337. void mm_exists (MAILSTREAM *stream,long number)
  338. {
  339.   /* Can't use this mechanism.  POP has no means of notifying the client of
  340.      new mail during the session. */
  341. }
  342.  
  343.  
  344. /* Message expunged
  345.  * Accepts: IMAP2 stream
  346.  *        message number
  347.  */
  348.  
  349. void mm_expunged (MAILSTREAM *stream,long number)
  350. {
  351.   /* This isn't used */
  352. }
  353.  
  354.  
  355. /* Mailbox found
  356.  * Accepts: Mailbox name
  357.  */
  358.  
  359. void mm_mailbox (char *string)
  360. {
  361.   /* This isn't used */
  362. }
  363.  
  364.  
  365. /* BBoard found
  366.  * Accepts: BBoard name
  367.  */
  368.  
  369. void mm_bboard (char *string)
  370. {
  371.   /* This isn't used */
  372. }
  373.  
  374. /* Notification event
  375.  * Accepts: IMAP2 stream
  376.  *        string to log
  377.  *        error flag
  378.  */
  379.  
  380. void mm_notify (MAILSTREAM *stream,char *string,long errflg)
  381. {
  382.   mm_log (string,errflg);    /* just do mm_log action */
  383. }
  384.  
  385.  
  386. /* Log an event for the user to see
  387.  * Accepts: string to log
  388.  *        error flag
  389.  */
  390.  
  391. void mm_log (char *string,long errflg)
  392. {
  393.   /* Not doing anything here for now */
  394. }
  395.  
  396.  
  397. /* Log an event to debugging telemetry
  398.  * Accepts: string to log
  399.  */
  400.  
  401. void mm_dlog (char *string)
  402. {
  403.   /* Not doing anything here for now */
  404. }
  405.  
  406.  
  407. /* Get user name and password for this host
  408.  * Accepts: host name
  409.  *        where to return user name
  410.  *        where to return password
  411.  *        trial count
  412.  */
  413.  
  414. void mm_login (char *host,char *username,char *password,long trial)
  415. {
  416.   strcpy (username,user);    /* set user name */
  417.   strcpy (password,pass);    /* and password */
  418. }
  419.  
  420. /* About to enter critical code
  421.  * Accepts: stream
  422.  */
  423.  
  424. void mm_critical (MAILSTREAM *stream)
  425. {
  426.   /* Not doing anything here for now */
  427. }
  428.  
  429.  
  430. /* About to exit critical code
  431.  * Accepts: stream
  432.  */
  433.  
  434. void mm_nocritical (MAILSTREAM *stream)
  435. {
  436.   /* Not doing anything here for now */
  437. }
  438.  
  439.  
  440. /* Disk error found
  441.  * Accepts: stream
  442.  *        system error code
  443.  *        flag indicating that mailbox may be clobbered
  444.  * Returns: abort flag
  445.  */
  446.  
  447. long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
  448. {
  449.   sleep (5);            /* can't do much better than this! */
  450.   return NIL;
  451. }
  452.  
  453.  
  454. /* Log a fatal error event
  455.  * Accepts: string to log
  456.  */
  457.  
  458. void mm_fatal (char *string)
  459. {
  460.   mm_log (string,ERROR);    /* shouldn't happen normally */
  461. }
  462.